import logging
import warnings
import os

import json
import yaml
from typing import cast, List, Dict, Any
from aiohttp import ClientSession

import chainlit as cl
from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
from autogen_agentchat.base import TaskResult
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.messages import ModelClientStreamingChunkEvent, TextMessage
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_core import CancellationToken
from autogen_core.models import ChatCompletionClient
from autogen_core.tools import FunctionTool

# 🔧 更全面的日志控制
logging.getLogger("autogen_core").setLevel(logging.WARNING)
logging.getLogger("autogen_agentchat").setLevel(logging.WARNING)
logging.getLogger("autogen_ext").setLevel(logging.WARNING)

# 关闭HTTP请求日志
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("urllib3").setLevel(logging.WARNING)
logging.getLogger("requests").setLevel(logging.WARNING)

# 关闭其他可能的噪音日志
logging.getLogger("aiohttp").setLevel(logging.WARNING)
logging.getLogger("asyncio").setLevel(logging.WARNING)
logging.getLogger("openai").setLevel(logging.WARNING)

# 抑制警告
warnings.filterwarnings("ignore", category=DeprecationWarning)
warnings.filterwarnings("ignore", category=UserWarning)

# 🔧 设置根日志级别，但保留ERROR和WARNING
logging.basicConfig(
    level=logging.WARNING, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)

# 在文件开头添加环境变量配置，控制 SocketIO 参数
os.environ["CHAINLIT_MAX_HTTP_BUFFER_SIZE"] = "1048576"  # 1MB

# 🔧 调整全局数据大小控制参数
MAX_RESPONSE_LENGTH = 9000  # 🔧 调整到8000字符，更适合K8s数据显示
MAX_SERVICE_PER_PAGE = 50  # 🔧 新增：每页显示的Service数量
MAX_TOTAL_SERVICES = 200  # 🔧 新增：总共显示的Service数量上限

# 🔧 新增：分页显示配置
PAGINATION_CONFIG = {
    "services_per_page": 50,
    "pods_per_page": 30,
    "deployments_per_page": 25,
    "nodes_per_page": 20,
    "default_per_page": 40,
}


# 🔧 新增：LLM显示长度Debug信息系统
def log_length_debug(stage: str, content: str, extra_info: dict = None) -> None:
    """记录各阶段的长度Debug信息"""
    len(content)
    char_count = len(content)
    word_count = len(content.split()) if content else 0
    line_count = content.count("\n") + 1 if content else 0

    debug_msg = f"🔍 [LENGTH_DEBUG] {stage}:"
    debug_msg += f"\n  📏 字符数: {char_count:,}"
    debug_msg += f"\n  📝 单词数: {word_count:,}"
    debug_msg += f"\n  📄 行数: {line_count:,}"
    debug_msg += f"\n  📊 字节数: {len(content.encode('utf-8')):,}"

    # 🔧 调整长度警告阈值
    if char_count > MAX_RESPONSE_LENGTH:
        debug_msg += f"\n  ⚠️  超出限制: +{char_count - MAX_RESPONSE_LENGTH:,} 字符"
    elif char_count > MAX_RESPONSE_LENGTH * 0.8:
        debug_msg += f"\n  🟡 接近限制: {char_count / MAX_RESPONSE_LENGTH * 100:.1f}%"
    else:
        debug_msg += f"\n  ✅ 长度正常: {char_count / MAX_RESPONSE_LENGTH * 100:.1f}%"

    # 额外信息
    if extra_info:
        for key, value in extra_info.items():
            debug_msg += f"\n  📋 {key}: {value}"

    # 内容预览（前100字符，增加预览长度）
    preview = content[:100].replace("\n", "\\n") if content else ""
    if len(content) > 100:
        preview += "..."
    debug_msg += f"\n  👀 内容预览: {preview}"

    print(debug_msg)


def get_content_stats(content: str) -> dict:
    """获取内容统计信息"""
    if not content:
        return {"chars": 0, "words": 0, "lines": 0, "bytes": 0}

    return {
        "chars": len(content),
        "words": len(content.split()),
        "lines": content.count("\n") + 1,
        "bytes": len(content.encode("utf-8")),
    }


def flatten(xss):
    return [x for xs in xss for x in xs]


# 🔧 更激进的数据截断策略
async def call_mcp_tool_directly(tool_name: str, tool_input: dict) -> str:
    """直接调用MCP工具的辅助函数"""
    try:
        mcp_tools = cl.user_session.get("mcp_tools", {})

        # 找到对应的MCP连接
        mcp_name = None
        for connection_name, tools in mcp_tools.items():
            if any(tool.get("name") == tool_name for tool in tools):
                mcp_name = connection_name
                break

        if not mcp_name:
            return f"❌ 工具 {tool_name} 未找到对应的MCP连接"

        # 获取MCP会话
        if not hasattr(cl.context.session, "mcp_sessions"):
            return "❌ MCP会话未初始化"

        mcp_session_info = cl.context.session.mcp_sessions.get(mcp_name)
        if not mcp_session_info:
            return f"❌ MCP连接 {mcp_name} 的会话未找到"

        mcp_session, _ = mcp_session_info

        print(
            f"🚀 执行MCP工具: {tool_name} with input type: {type(tool_input)} value: {tool_input}"
        )

        # 调用工具 - 确保tool_input是字典，即使为空
        result = await mcp_session.call_tool(
            tool_name, tool_input if tool_input is not None else {}
        )

        # 🔧 原始结果长度Debug
        raw_result_str = str(result)
        log_length_debug(
            "MCP原始结果",
            raw_result_str,
            {"工具名称": tool_name, "输入参数": str(tool_input)},
        )

        print(f"✅ MCP工具调用成功，结果长度: {len(raw_result_str)}")

        # 🔧 处理不同类型的结果
        if isinstance(result, str):
            try:
                json_data = json.loads(result)
                if isinstance(json_data, list) and len(json_data) > 0:
                    print(f"📊 解析到 {len(json_data)} 条记录")

                    # 🔧 JSON数据解析Debug
                    log_length_debug(
                        "JSON数据解析",
                        result,
                        {"记录数量": len(json_data), "数据类型": "JSON列表"},
                    )

                    # 🔧 根据资源类型和数据量选择处理方式
                    resource_kind = (
                        tool_input.get("kind", "").lower() if tool_input else ""
                    )

                    formatted_result = ""
                    # 🔧 新增：Node特殊处理
                    if "node" in tool_name.lower() or resource_kind == "node":
                        formatted_result = format_node_list_comprehensive(json_data)
                    elif "service" in tool_name.lower() or resource_kind == "service":
                        formatted_result = format_service_list_comprehensive(json_data)
                    elif len(json_data) > 100:
                        # 其他大数据集使用分页
                        page_response, _ = create_paginated_response(
                            json_data, resource_kind or "Resource", 1
                        )
                        formatted_result = page_response
                    else:
                        formatted_result = format_k8s_table_enhanced(
                            json_data, len(json_data)
                        )

                    log_length_debug(
                        "数据格式化完成",
                        formatted_result,
                        {
                            "原始记录数": len(json_data),
                            "资源类型": resource_kind,
                            "格式化类型": "智能分页",
                        },
                    )

                    return formatted_result
                else:
                    # 🔧 调整截断长度
                    truncated_result = result[:MAX_RESPONSE_LENGTH]
                    log_length_debug(
                        "非列表数据截断",
                        truncated_result,
                        {
                            "原始长度": len(result),
                            "截断长度": MAX_RESPONSE_LENGTH,
                            "是否截断": len(result) > MAX_RESPONSE_LENGTH,
                        },
                    )
                    return truncated_result
            except json.JSONDecodeError as e:
                print(f"❌ JSON解析失败: {e}")
                truncated_result = result[:MAX_RESPONSE_LENGTH]
                log_length_debug(
                    "JSON解析失败-截断",
                    truncated_result,
                    {
                        "原始长度": len(result),
                        "截断长度": MAX_RESPONSE_LENGTH,
                        "错误": str(e),
                    },
                )
                return truncated_result

        # 🔧 处理其他类型的结果
        if hasattr(result, "content") and result.content:
            # 处理MCP返回的复杂对象
            if isinstance(result.content, list) and len(result.content) > 0:
                first_content = result.content[0]
                if hasattr(first_content, "text"):
                    content_text = first_content.text
                    try:
                        json_data = json.loads(content_text)
                        if isinstance(json_data, list):
                            resource_kind = (
                                tool_input.get("kind", "").lower() if tool_input else ""
                            )
                            # 🔧 新增：Node特殊处理
                            if "node" in tool_name.lower() or resource_kind == "node":
                                return format_node_list_comprehensive(json_data)
                            elif (
                                "service" in tool_name.lower()
                                or resource_kind == "service"
                            ):
                                return format_service_list_comprehensive(json_data)
                            elif len(json_data) > 50:
                                page_response, _ = create_paginated_response(
                                    json_data, resource_kind or "Resource", 1
                                )
                                return page_response
                            else:
                                return format_k8s_table_enhanced(
                                    json_data, len(json_data)
                                )
                    except json.JSONDecodeError:
                        pass

                    final_result = content_text[:MAX_RESPONSE_LENGTH]
                    log_length_debug(
                        "复杂对象内容截断",
                        final_result,
                        {
                            "原始长度": len(content_text),
                            "截断长度": MAX_RESPONSE_LENGTH,
                            "结果类型": type(result).__name__,
                        },
                    )
                    return final_result

        # 默认处理
        final_result = str(result)[:MAX_RESPONSE_LENGTH]
        log_length_debug(
            "默认结果截断",
            final_result,
            {
                "原始长度": len(str(result)),
                "截断长度": MAX_RESPONSE_LENGTH,
                "结果类型": type(result).__name__,
            },
        )
        return final_result

    except Exception as e:
        error_msg = f"❌ 工具调用失败: {e}"
        print(error_msg)
        log_length_debug(
            "错误消息", error_msg, {"工具名称": tool_name, "错误类型": type(e).__name__}
        )
        return error_msg


def format_large_dataset(data: List[dict], tool_name: str) -> str:
    """处理大数据集的特殊格式化"""
    total_count = len(data)
    display_count = 30  # 大数据集只显示前30条

    # 🔧 新增：大数据集处理Debug
    log_length_debug(
        "大数据集处理开始",
        "",
        {"总记录数": total_count, "显示记录数": display_count, "工具名称": tool_name},
    )

    summary = f"📊 **{tool_name} 查询结果**\n\n"
    summary += f"🔢 **总计：** {total_count} 条记录\n"
    summary += f"👀 **当前显示：** 前 {display_count} 条\n\n"

    # 生成数据统计
    stats = generate_data_statistics(data)
    log_length_debug("数据统计生成", stats, {"统计类型": "数据分布统计"})
    summary += stats

    # 显示前30条的简化表格
    display_data = data[:display_count]
    table = format_k8s_table_compact(display_data)
    log_length_debug(
        "紧凑表格生成", table, {"显示行数": len(display_data), "表格类型": "紧凑表格"}
    )

    summary += "\n" + table
    summary += f"\n\n💡 **提示：** 还有 {total_count - display_count} 条记录未显示。"
    summary += "\n**建议：** 使用更具体的查询条件来缩小结果范围。"

    log_length_debug(
        "大数据集格式化完成",
        summary,
        {"最终记录数": display_count, "总记录数": total_count},
    )

    return summary


def generate_data_statistics(data: List[dict]) -> str:
    """生成数据统计信息"""

    # 统计namespace分布
    namespaces = {}
    types = {}

    for item in data:
        if isinstance(item, dict):
            ns = item.get("namespace", item.get("Namespace", "default"))
            if ns:
                namespaces[ns] = namespaces.get(ns, 0) + 1

            type_val = item.get("type", item.get("Type", item.get("kind", "Unknown")))
            if type_val:
                types[type_val] = types.get(type_val, 0) + 1

    stats_text = "📈 **数据统计：**\n"

    # Top 5 namespaces
    if namespaces:
        top_ns = sorted(namespaces.items(), key=lambda x: x[1], reverse=True)[:5]
        stats_text += "**Namespace分布：** "
        stats_text += ", ".join([f"{ns}({count})" for ns, count in top_ns])
        if len(namespaces) > 5:
            stats_text += f" +{len(namespaces) - 5}more"
        stats_text += "\n"

    # Types
    if types:
        top_types = sorted(types.items(), key=lambda x: x[1], reverse=True)[:3]
        stats_text += "**类型分布：** "
        stats_text += ", ".join([f"{t}({count})" for t, count in top_types])
        if len(types) > 3:
            stats_text += f" +{len(types) - 3}more"
        stats_text += "\n"

    return stats_text


def format_k8s_table_compact(data: List[dict]) -> str:
    """紧凑格式的K8s表格"""
    if not data:
        return "没有数据"

    # 只显示最重要的4列
    priority_fields = ["name", "namespace", "type", "status"]
    headers = []

    sample_item = data[0]
    if isinstance(sample_item, dict):
        for field in priority_fields:
            for key in sample_item.keys():
                if field in key.lower() and key not in headers:
                    headers.append(key)
                    break

        # 如果没找到足够的列，补充其他重要字段
        if len(headers) < 4:
            extra_fields = ["ready", "age", "ports", "cluster-ip"]
            for field in extra_fields:
                for key in sample_item.keys():
                    if field in key.lower() and key not in headers and len(headers) < 4:
                        headers.append(key)
                        break

    if not headers:
        return "无法解析数据结构"

    # 构建紧凑表格
    table = "| " + " | ".join(headers) + " |\n"
    table += "| " + " | ".join(["---"] * len(headers)) + " |\n"

    for item in data:
        if isinstance(item, dict):
            row_values = []
            for header in headers:
                value = item.get(header, "")
                if isinstance(value, dict):
                    value = value.get("name", str(value)[:15])
                elif isinstance(value, list):
                    if len(value) > 0:
                        value = f"[{len(value)}]"
                    else:
                        value = "[]"

                value = str(value).replace("\n", " ").replace("|", "\\|")
                # 紧凑显示，每个单元格最多20字符
                if len(value) > 20:
                    value = value[:17] + "..."
                row_values.append(value)
            table += "| " + " | ".join(row_values) + " |\n"

    return table


def format_k8s_table_enhanced(data: List[dict], total_count: int) -> str:
    """增强版K8s表格格式化"""
    if not data:
        return "没有找到任何数据。"

    display_count = len(data)
    summary = f"📊 **查询结果：** 总共 {total_count} 条记录"

    if total_count > display_count:
        summary += f"，当前显示前 {display_count} 条"
    else:
        summary += "（全部显示）"

    summary += "\n\n"

    # 使用紧凑格式
    table = format_k8s_table_compact(data)

    result = summary + table

    if total_count > display_count:
        result += f"\n\n💡 **提示：** 还有 {total_count - display_count} 条记录未显示。"

    return result


def create_ultra_safe_summary(data: List[dict], total_count: int) -> str:
    """超级安全的摘要生成"""
    if not data:
        return "没有数据"

    summary = f"📊 查询结果: {total_count} 条记录\n\n"

    # 只显示前3条的核心信息
    for i, item in enumerate(data[:3]):
        if isinstance(item, dict):
            name = str(item.get("name", item.get("Name", f"Item-{i + 1}")))[:20]
            ns = str(item.get("namespace", item.get("Namespace", "")))[:15]
            status = str(item.get("status", item.get("Status", "")))[:10]

            line = f"{i + 1}. {name}"
            if ns:
                line += f" ({ns})"
            if status:
                line += f" [{status}]"
            summary += line + "\n"

    if total_count > 3:
        summary += f"\n... 还有 {total_count - 3} 条记录"

    return summary[:MAX_RESPONSE_LENGTH]


def create_minimal_summary(data: List[dict], total_count: int) -> str:
    """最小化摘要"""
    if not data:
        return "无数据"

    first_item = data[0] if data else {}
    name = str(first_item.get("name", "Unknown"))[:30]

    return f"📊 共 {total_count} 条记录，首项: {name}" + (
        " ..." if total_count > 1 else ""
    )


def format_k8s_table_strict(data: List[dict], total_count: int) -> str:
    """超级严格的K8s表格格式化"""
    if not data:
        return "没有找到任何数据。"

    # 🔧 最多显示15条记录
    display_data = data[:15]

    summary = f"📊 **查询结果** (显示 {len(display_data)}/{total_count} 条)\n\n"

    if total_count > 15:
        summary += "⚠️ **数据量过大，仅显示前15条记录**\n\n"

    # 🔧 只显示最核心的3列
    headers = []
    if display_data:
        sample_item = display_data[0]
        if isinstance(sample_item, dict):
            # 只保留最重要的3个字段
            priority_fields = ["name", "namespace", "status"]

            for field in priority_fields:
                for key in sample_item.keys():
                    if field in key.lower() and key not in headers:
                        headers.append(key)
                        break

            # 如果没有找到优先字段，取前3个
            if len(headers) < 3:
                available_keys = [k for k in sample_item.keys() if k not in headers]
                headers.extend(available_keys[: 3 - len(headers)])

    if not headers:
        return create_emergency_summary(display_data, total_count)

    # 构建极简表格
    table = "| " + " | ".join(headers[:3]) + " |\n"  # 最多3列
    table += "| " + " | ".join(["---"] * len(headers[:3])) + " |\n"

    for item in display_data:
        if isinstance(item, dict):
            row_values = []
            for header in headers[:3]:
                value = str(item.get(header, ""))[:15]  # 每个单元格最多15字符
                value = value.replace("\n", " ").replace("|", "\\|")
                row_values.append(value)
            table += "| " + " | ".join(row_values) + " |\n"

    result = summary + table

    # 🔧 终极安全检查
    if len(result) > 1500:
        return create_emergency_summary(display_data, total_count)

    return result


def create_emergency_summary(data: List[dict], total_count: int) -> str:
    """紧急情况下的极简摘要"""
    if not data:
        return "没有数据"

    # 只显示前5条的name字段
    summary = f"📊 **查询结果摘要** ({total_count} 条记录)\n\n"

    for i, item in enumerate(data[:5]):
        if isinstance(item, dict):
            name = item.get("name", item.get("Name", f"Item-{i + 1}"))
            namespace = item.get("namespace", item.get("Namespace", ""))
            if namespace:
                summary += f"{i + 1}. {name} (ns: {namespace})\n"
            else:
                summary += f"{i + 1}. {name}\n"

    if total_count > 5:
        summary += f"\n... 还有 {total_count - 5} 条记录未显示"

    return summary


def format_k8s_table(data: List[dict], max_rows: int = 50) -> str:  # 🔧 适中的限制
    """格式化K8s资源为表格"""
    if not data:
        return "没有找到任何数据。"

    total_count = len(data)

    # 🔧 适中的分批显示机制
    if total_count > max_rows:
        display_data = data[:max_rows]
        summary = (
            f"📊 **查询结果：** 总共 {total_count} 条记录，当前显示前 {max_rows} 条\n\n"
        )
        summary += f"⚠️ **注意：** 数据量较大，仅显示前 {max_rows} 条。如需查看更多数据，请使用更具体的筛选条件。\n\n"
    else:
        display_data = data
        summary = f"📊 **查询结果：** 总共 {total_count} 条记录（全部显示）\n\n"

    # 智能提取表头
    headers = []
    if display_data:
        sample_item = display_data[0]
        if isinstance(sample_item, dict):
            # K8s资源关键字段
            k8s_priority_fields = [
                "name",
                "kind",
                "namespace",
                "phase",
                "status",
                "ready",
                "node",
                "type",
                "clusterip",
                "cluster-ip",
                "external-ip",
                "port",
                "ports",
                "age",
                "restarts",
            ]

            # 先添加匹配的优先字段
            for priority_field in k8s_priority_fields:
                for key in sample_item.keys():
                    if priority_field in key.lower() and key not in headers:
                        headers.append(key)
                        break

            # 再添加其他字段，总共不超过10个
            for key in sample_item.keys():
                if key not in headers and len(headers) < 10:
                    headers.append(key)

    if not headers:
        return (
            summary
            + "```json\n"
            + json.dumps(data[:3], indent=2, ensure_ascii=False)
            + "\n```"
        )

    # 构建表格
    table = "| " + " | ".join(headers) + " |\n"
    table += "| " + " | ".join(["---"] * len(headers)) + " |\n"

    for item in display_data:
        if isinstance(item, dict):
            row_values = []
            for header in headers:
                value = item.get(header, "")
                if isinstance(value, dict):
                    value = value.get("name", value.get("type", str(value)[:30]))
                elif isinstance(value, list):
                    if len(value) > 0 and isinstance(value[0], dict):
                        port_info = []
                        for v in value[:2]:
                            if isinstance(v, dict):
                                port_str = f"{v.get('port', '')}"
                                if v.get("protocol"):
                                    port_str += f"/{v.get('protocol')}"
                                port_info.append(port_str)
                            else:
                                port_info.append(str(v))
                        value = ",".join(port_info)
                        if len(value) > 2:
                            value += f" +{len(value) - 2}more"
                    else:
                        value = f"[{len(value)} items]"

                value = str(value)
                value = value.replace("\n", " ").replace("|", "\\|")
                if len(value) > 40:  # Service字段可以稍微长一些
                    value = value[:37] + "..."
                row_values.append(value)
            table += "| " + " | ".join(row_values) + " |\n"

    return summary + table


def format_service_list_comprehensive(services: List[dict]) -> str:
    """专门为Service列表设计的格式化函数 - 支持分页"""
    total_count = len(services)

    print(f"🔍 开始格式化 {total_count} 个Service")

    # 🔧 Service格式化Debug
    log_length_debug(
        "Service格式化开始",
        "",
        {"Service总数": total_count, "格式化类型": "Service分页列表"},
    )

    # 🔧 使用分页显示
    if total_count > MAX_SERVICE_PER_PAGE:
        page_response, has_more = create_paginated_response(services, "Service", 1)

        # 添加Service统计信息
        stats = generate_service_statistics(services)
        log_length_debug("Service统计生成", stats, {"统计类型": "Service统计信息"})

        # 在分页内容前插入统计信息
        stats_section = f"📈 **Service统计信息：**\n{stats}\n\n"
        final_response = page_response.replace(
            "📊 **Service 查询结果", f"{stats_section}📊 **Service 查询结果"
        )

        if has_more:
            final_response += "\n\n🔧 **使用提示：**\n"
            final_response += '• 询问"显示第2页的Service"查看更多\n'
            final_response += '• 询问"显示namespace xxx的Service"按命名空间筛选\n'
            final_response += '• 询问"显示ClusterIP类型的Service"按类型筛选'

        log_length_debug(
            "Service分页响应完成",
            final_response,
            {
                "显示Service数": min(MAX_SERVICE_PER_PAGE, total_count),
                "总Service数": total_count,
                "是否分页": has_more,
            },
        )

        return final_response

    else:
        # 数量不多时，使用原有逻辑但优化显示
        return format_service_list_full(services)


def format_service_list_full(services: List[dict]) -> str:
    """显示完整Service列表（数量较少时）"""
    total_count = len(services)

    report = "📊 **Kubernetes Service 完整列表**\n\n"
    report += f"🔢 **总计：** {total_count} 个Service\n\n"

    # 生成Service统计
    stats = generate_service_statistics(services)
    report += stats + "\n"

    # 按namespace分组显示
    service_by_ns = {}
    for svc in services:
        ns = svc.get("namespace", svc.get("Namespace", "default"))
        if ns not in service_by_ns:
            service_by_ns[ns] = []
        service_by_ns[ns].append(svc)

    report += "📋 **Service详细列表：**\n\n"

    for namespace, ns_services in service_by_ns.items():
        if len(service_by_ns) > 1:
            report += f"### Namespace: {namespace} ({len(ns_services)} 个Service)\n\n"

        table = format_service_table_optimized(ns_services)
        report += table + "\n\n"

    return report


def generate_service_statistics(services: List[dict]) -> str:
    """生成Service统计信息"""

    # 统计各维度数据
    namespaces = {}
    types = {}
    ports_count = {}

    for svc in services:
        if isinstance(svc, dict):
            # Namespace统计
            ns = svc.get("namespace", svc.get("Namespace", "default"))
            namespaces[ns] = namespaces.get(ns, 0) + 1

            # Type统计
            svc_type = svc.get("type", svc.get("Type", "ClusterIP"))
            types[svc_type] = types.get(svc_type, 0) + 1

            # 端口统计
            ports = svc.get("ports", svc.get("Ports", []))
            if isinstance(ports, list):
                port_count = len(ports)
                ports_count[port_count] = ports_count.get(port_count, 0) + 1

    stats_text = "📈 **Service统计信息：**\n"

    # Namespace分布
    if namespaces:
        top_ns = sorted(namespaces.items(), key=lambda x: x[1], reverse=True)
        stats_text += "**Namespace分布：** "
        ns_info = [f"{ns}({count})" for ns, count in top_ns[:10]]  # 显示前10个
        stats_text += ", ".join(ns_info)
        if len(namespaces) > 10:
            stats_text += f" +{len(namespaces) - 10}more"
        stats_text += "\n"

    # Service类型分布
    if types:
        stats_text += "**Service类型：** "
        type_info = [f"{t}({count})" for t, count in types.items()]
        stats_text += ", ".join(type_info) + "\n"

    # 端口统计
    if ports_count:
        stats_text += "**端口分布：** "
        port_info = [
            f"{count}端口({svc_count}个服务)"
            for count, svc_count in sorted(ports_count.items())
        ]
        stats_text += ", ".join(port_info[:5]) + "\n"

    return stats_text


def format_service_table_optimized(services: List[dict]) -> str:
    """优化的Service表格格式化"""
    if not services:
        return "没有Service数据"

    # Service的核心字段，按重要性排序
    priority_fields = [
        ("name", "服务名称"),
        ("namespace", "命名空间"),
        ("type", "类型"),
        ("cluster-ip", "集群IP"),
        ("external-ip", "外部IP"),
        ("ports", "端口"),
        ("age", "运行时间"),
    ]

    # 匹配可用字段
    headers = []
    header_labels = []
    sample_svc = services[0]

    for field, label in priority_fields:
        for key in sample_svc.keys():
            if (
                field.replace("-", "").lower() in key.replace("-", "").lower()
                and key not in headers
            ):
                headers.append(key)
                header_labels.append(label)
                break
        if len(headers) >= 6:  # 最多6列
            break

    # 构建表格
    table = "| " + " | ".join(header_labels) + " |\n"
    table += "| " + " | ".join(["---"] * len(header_labels)) + " |\n"

    for svc in services:
        if isinstance(svc, dict):
            row_values = []
            for header in headers:
                value = svc.get(header, "")

                # 特殊处理不同字段类型
                if isinstance(value, list) and "port" in header.lower():
                    # 端口信息格式化
                    port_strs = []
                    for port in value[:2]:  # 最多显示2个端口
                        if isinstance(port, dict):
                            port_str = f"{port.get('port', '')}"
                            if port.get("protocol"):
                                port_str += f"/{port.get('protocol')}"
                            if port.get("targetPort") and port.get(
                                "targetPort"
                            ) != port.get("port"):
                                port_str += f"→{port.get('targetPort')}"
                            port_strs.append(port_str)
                        else:
                            port_strs.append(str(port))
                    value = ",".join(port_strs)
                    if len(value) > 2:
                        value += f"+{len(value) - 2}"
                elif isinstance(value, list):
                    value = f"[{len(value)}项]"
                elif isinstance(value, dict):
                    value = value.get("name", str(value)[:20])

                value = str(value).replace("\n", " ").replace("|", "\\|")

                # 🔧 调整字段长度限制，更宽松
                max_length = 35 if "name" in header.lower() else 25
                if len(value) > max_length:
                    value = value[: max_length - 3] + "..."

                row_values.append(value)

            table += "| " + " | ".join(row_values) + " |\n"

    return table


# 🔧 新增：智能分页处理函数
def create_paginated_response(
    data: List[dict], resource_type: str, page: int = 1
) -> tuple[str, bool]:
    """创建分页响应，返回(内容, 是否有更多页)"""
    total_count = len(data)
    per_page = PAGINATION_CONFIG.get(
        f"{resource_type.lower()}s_per_page", PAGINATION_CONFIG["default_per_page"]
    )

    start_idx = (page - 1) * per_page
    end_idx = start_idx + per_page
    page_data = data[start_idx:end_idx]

    has_more = end_idx < total_count
    total_pages = (total_count + per_page - 1) // per_page

    log_length_debug(
        "分页数据处理",
        "",
        {
            "总记录数": total_count,
            "当前页": page,
            "总页数": total_pages,
            "每页数量": per_page,
            "当前页记录数": len(page_data),
            "是否有更多": has_more,
        },
    )

    # 生成页面内容
    response = f"📊 **{resource_type} 查询结果 - 第 {page}/{total_pages} 页**\n\n"
    response += f"🔢 **总计：** {total_count} 个{resource_type}\n"
    response += f"👀 **当前页：** {len(page_data)} 个{resource_type} ({start_idx + 1}-{min(end_idx, total_count)})\n\n"

    # 根据资源类型选择格式化函数
    if resource_type.lower() == "service":
        table_content = format_service_table_optimized(page_data)
    else:
        table_content = format_k8s_table_optimized(page_data, resource_type)

    response += table_content

    # 添加分页导航提示
    if has_more:
        response += "\n\n📄 **分页导航：**\n"
        response += f"• 当前显示第 {page} 页，共 {total_pages} 页\n"
        response += f"• 还有 {total_count - end_idx} 个{resource_type}未显示\n"
        response += f'💡 **查看更多：** 可以询问"显示第{page + 1}页的{resource_type}"\n'

    log_length_debug(
        "分页响应完成",
        response,
        {"页面": f"{page}/{total_pages}", "是否有更多": has_more},
    )

    return response, has_more


# 🔧 通用的K8s资源表格格式化
def format_k8s_table_optimized(data: List[dict], resource_type: str) -> str:
    """优化的K8s资源表格格式化"""
    if not data:
        return f"没有{resource_type}数据"

    # 根据资源类型定义优先字段
    resource_fields = {
        "pod": [
            ("name", "Pod名称"),
            ("namespace", "命名空间"),
            ("status", "状态"),
            ("ready", "就绪"),
            ("node", "节点"),
            ("age", "运行时间"),
        ],
        "deployment": [
            ("name", "部署名称"),
            ("namespace", "命名空间"),
            ("ready", "就绪"),
            ("up-to-date", "最新"),
            ("available", "可用"),
            ("age", "运行时间"),
        ],
        "node": [
            ("name", "节点名称"),
            ("status", "状态"),
            ("roles", "角色"),
            ("age", "运行时间"),
            ("version", "版本"),
        ],
        "default": [
            ("name", "名称"),
            ("namespace", "命名空间"),
            ("status", "状态"),
            ("age", "运行时间"),
        ],
    }

    priority_fields = resource_fields.get(
        resource_type.lower(), resource_fields["default"]
    )

    # 匹配字段
    headers = []
    header_labels = []
    sample_item = data[0]

    for field, label in priority_fields:
        for key in sample_item.keys():
            if (
                field.replace("-", "").lower() in key.replace("-", "").lower()
                and key not in headers
            ):
                headers.append(key)
                header_labels.append(label)
                break

    # 构建表格
    table = "| " + " | ".join(header_labels) + " |\n"
    table += "| " + " | ".join(["---"] * len(header_labels)) + " |\n"

    for item in data:
        if isinstance(item, dict):
            row_values = []
            for header in headers:
                value = item.get(header, "")

                if isinstance(value, (list, dict)):
                    if isinstance(value, list):
                        value = f"[{len(value)}]" if value else "[]"
                    else:
                        value = value.get("name", str(value)[:20])

                value = str(value).replace("\n", " ").replace("|", "\\|")
                if len(value) > 30:
                    value = value[:27] + "..."

                row_values.append(value)

            table += "| " + " | ".join(row_values) + " |\n"

    return table


# 🔧 添加缺失的函数
def convert_mcp_tools_to_agentchat_tools(
    mcp_tools_list: List[Dict[str, Any]],
) -> List[FunctionTool]:
    """将MCP工具字典转换为autogen_core.tools.FunctionTool对象列表"""
    converted_tools = []

    for tool_dict in mcp_tools_list:
        tool_name = tool_dict["name"]
        tool_description = tool_dict.get("description", "")
        input_schema = tool_dict.get("input_schema", {})  # 获取input_schema

        # 为每个工具动态创建一个包装函数
        def create_wrapper(name, desc, schema):  # 传入input_schema
            async def tool_wrapper(**kwargs: Any) -> str:
                # 这里的kwargs是LLM生成的参数字典
                print(
                    f"DEBUG: tool_wrapper called for {name} with kwargs type: {type(kwargs)} value: {kwargs}"
                )

                # 🔧 改进的参数处理逻辑
                processed_kwargs = {}

                # 情况1: 如果kwargs中有嵌套的kwargs键
                if "kwargs" in kwargs and isinstance(kwargs["kwargs"], dict):
                    actual_kwargs = kwargs["kwargs"]
                    print(f"DEBUG: 检测到嵌套kwargs，解包: {actual_kwargs}")
                else:
                    actual_kwargs = kwargs
                    print(f"DEBUG: 使用直接kwargs: {actual_kwargs}")

                # 🔧 添加参数名映射，解决LLM参数名与MCP工具参数名不匹配的问题
                parameter_mapping = {
                    "resource_type": "kind",
                    "resource_kind": "kind",
                    "type": "kind",
                    "api_version": "api_version",
                    "apiVersion": "api_version",
                    "namespace": "namespace",
                    "ns": "namespace",
                    "name": "name",
                    "selector": "selector",
                    "labels": "selector",
                }

                # 应用参数映射
                mapped_kwargs = {}
                for key, value in actual_kwargs.items():
                    mapped_key = parameter_mapping.get(key, key)
                    mapped_kwargs[mapped_key] = value
                    print(f"DEBUG: 参数映射 {key} -> {mapped_key} = {value}")

                # 根据input_schema验证和处理参数
                if schema and schema.get("properties"):
                    schema_props = schema["properties"]
                    for prop_name, prop_details in schema_props.items():
                        if prop_name in mapped_kwargs:
                            processed_kwargs[prop_name] = mapped_kwargs[prop_name]
                        elif prop_name in actual_kwargs:  # 备用：直接匹配
                            processed_kwargs[prop_name] = actual_kwargs[prop_name]
                        elif prop_details.get("default"):
                            processed_kwargs[prop_name] = prop_details["default"]
                        # 如果参数是必须的但没有提供，记录警告
                        elif schema.get("required") and prop_name in schema.get(
                            "required", []
                        ):
                            print(f"⚠️ 缺少必需参数: {prop_name}")
                            print(f"   可用的映射后参数: {list(mapped_kwargs.keys())}")
                            print(f"   原始参数: {list(actual_kwargs.keys())}")
                else:
                    # 如果没有schema，直接使用映射后的参数
                    processed_kwargs = mapped_kwargs

                print(f"DEBUG: 最终处理后的参数: {processed_kwargs}")
                return await call_mcp_tool_directly(name, processed_kwargs)

            tool_wrapper.__doc__ = desc
            tool_wrapper.__name__ = name
            return tool_wrapper

        function_tool = FunctionTool(
            name=tool_name,
            description=tool_description,
            func=create_wrapper(tool_name, tool_description, input_schema),
        )
        converted_tools.append(function_tool)

    return converted_tools


@cl.on_mcp_connect
async def on_mcp(connection, session: ClientSession):
    print(f"🔗 MCP连接建立: {connection.name}")
    try:
        result = await session.list_tools()
        tools = [
            {
                "name": t.name,
                "description": t.description,
                "input_schema": t.inputSchema,
            }
            for t in result.tools
        ]

        print(f"📋 从 {connection.name} 获取到 {len(tools)} 个工具:")
        for tool in tools:
            print(f"  - {tool['name']}: {tool['description']}")

        mcp_tools = cl.user_session.get("mcp_tools", {})
        mcp_tools[connection.name] = tools
        cl.user_session.set("mcp_tools", mcp_tools)

        # 动态更新Agent
        await update_agents_with_tools()

    except Exception as e:
        print(f"❌ MCP连接失败: {e}")


async def update_agents_with_tools():
    """动态更新Agent以包含MCP工具"""
    mcp_tools_dicts = cl.user_session.get("mcp_tools", {})
    all_mcp_tools_flat_list = flatten([tools for _, tools in mcp_tools_dicts.items()])

    # 将MCP工具字典转换为FunctionTool对象列表
    converted_autogen_tools = convert_mcp_tools_to_agentchat_tools(
        all_mcp_tools_flat_list
    )
    print(f"🔄 转换为 Autogen 兼容工具数量: {len(converted_autogen_tools)}")

    # 🔧 修复：添加模型配置的安全加载
    model_config = cl.user_session.get("model_config")
    if not model_config:
        print("⚠️ 模型配置未找到，尝试重新加载...")
        try:
            with open("model_config.yaml", "r") as f:
                model_config = yaml.safe_load(f)
            cl.user_session.set("model_config", model_config)
            print("✅ 模型配置重新加载成功")
        except Exception as e:
            print(f"❌ 加载模型配置失败: {e}")
            return

    model_client = ChatCompletionClient.load_component(model_config)

    # 重新创建 k8s_admin, k8s_report 和 user agents
    k8s_admin = AssistantAgent(
        name="k8s_admin",
        model_client=model_client,
        system_message="""你是专业的K8s管理员助手，**必须使用MCP工具**获取真实数据。

🎯 **强制要求：**
1. **禁止**提供模板化或示例性回答
2. **必须**使用可用的MCP工具获取真实K8s集群数据
3. **必须**调用工具后再进行分析
4. **完整显示**所有查询到的资源信息，不要遗漏任何数据

🔧 **工具调用参数：**
- 使用 list_resources 工具时，参数名为 `kind`（不是resource_type）
- 示例：list_resources(kind="Service") 获取所有Service
- 示例：list_resources(kind="Pod") 获取所有Pod
- 示例：list_resources(kind="Deployment") 获取所有Deployment

🔧 **工作流程：**
1. 收到用户请求后，**立即使用相应的MCP工具**
2. 获取真实数据后，格式化为清晰的表格
3. 提供基于真实数据的分析
4. **确保显示所有查询到的资源**，不要省略或简化

📊 **数据展示要求：**
- 显示所有查询到的资源（不只是部分）
- 包含完整的字段信息
- 对于大量数据，明确说明总数和当前显示范围
- 如果数据量大，提供分批查询的建议

⚠️ **重要：**
- 绝对不能编造或猜测K8s资源信息
- 所有回答必须基于工具调用的真实结果
- 使用正确的参数名调用工具""",
        tools=converted_autogen_tools,
        model_client_stream=True,
    )

    k8s_report = AssistantAgent(
        name="k8s_report",
        model_client=model_client,
        system_message="""你是K8s报告生成专家。

🎯 职责：
1. 基于k8s_admin获取的真实数据生成专业报告
2. 分析K8s集群状态和资源使用情况
3. 提供优化建议和最佳实践
4. 生成结构化的Markdown报告

📋 报告格式：
- 清晰的标题结构
- 关键指标表格展示
- 问题和建议分类列出
- 包含操作建议和命令示例

⚠️ **重要：** 只能基于k8s_admin提供的真实数据生成报告""",
        tools=[],
        model_client_stream=True,
    )

    user = UserProxyAgent(
        name="user",
        input_func=user_action_func,
    )

    termination = TextMentionTermination("不同意", sources=["user"])
    group_chat = RoundRobinGroupChat(
        [k8s_admin, k8s_report, user], termination_condition=termination
    )

    cl.user_session.set("team", group_chat)

    print(f"🔄 Agent团队已更新，k8s_admin现在有 {len(converted_autogen_tools)} 个工具")


@cl.step(type="tool")
async def call_tool(tool_use):
    """处理工具调用请求"""
    tool_name = tool_use.name
    tool_input = tool_use.input

    current_step = cl.context.current_step
    current_step.name = tool_name

    print(f"🔧 Chainlit捕获到工具调用请求: {tool_name}")
    print(f"DEBUG: Chainlit tool_input type: {type(tool_input)} value: {tool_input}")

    # 检查并解包嵌套的kwargs，因为Chainlit可能会传递这样的结构
    if (
        isinstance(tool_input, dict)
        and "kwargs" in tool_input
        and isinstance(tool_input["kwargs"], dict)
    ):
        processed_tool_input = tool_input["kwargs"]
    else:
        processed_tool_input = tool_input

    # 直接调用MCP工具的辅助函数
    result = await call_mcp_tool_directly(tool_name, processed_tool_input)
    current_step.output = result

    return result


async def user_input_func(
    prompt: str, cancellation_token: CancellationToken | None = None
) -> str:
    """获取用户输入。"""
    try:
        response = await cl.AskUserMessage(content=prompt).send()
    except TimeoutError:
        return "User did not provide any input within the time limit."
    if response:
        return response["output"]
    else:
        return "User did not provide any input."


async def user_action_func(
    prompt: str, cancellation_token: CancellationToken | None = None
) -> str:
    """Get user action from the UI for the user proxy agent."""
    try:
        response = await cl.AskActionMessage(
            content="是否继续执行？",
            actions=[
                cl.Action(name="approve", label="同意", payload={"value": "approve"}),
                cl.Action(name="reject", label="不同意", payload={"value": "reject"}),
            ],
        ).send()
    except TimeoutError:
        return "User did not provide any input within the time limit."
    if response and response.get("payload"):
        if response.get("payload").get("value") == "approve":
            return "同意."
        else:
            return "不同意."
    else:
        return "User did not provide any input."


@cl.on_chat_start
async def start_chat() -> None:
    print("🚀 开始聊天会话")
    cl.user_session.set("mcp_tools", {})

    # 加载模型配置
    with open("model_config.yaml", "r") as f:
        model_config = yaml.safe_load(f)
    cl.user_session.set("model_config", model_config)
    model_client = ChatCompletionClient.load_component(model_config)

    # 初始创建agents，此时tools为空，等待MCP连接后更新
    k8s_admin = AssistantAgent(
        name="k8s_admin",
        model_client=model_client,
        system_message="""你是专业的K8s管理员助手。

🎯 **职责：**
1. 理解用户的K8s查询需求
2. 等待MCP工具连接后获取真实集群数据
3. 基于真实数据提供分析

⚠️ **当前状态：** 等待MCP服务器连接
- 如果用户询问K8s信息，请告知需要先连接MCP服务器
- 连接后将能够查询真实的集群数据""",
        tools=[],  # 初始时为空，等待MCP连接后更新
        model_client_stream=True,
    )

    k8s_report = AssistantAgent(
        name="k8s_report",
        model_client=model_client,
        system_message="""你是K8s报告生成专家。

🎯 职责：
1. 基于k8s_admin获取的真实数据生成专业报告
2. 分析K8s集群状态和资源使用情况
3. 提供优化建议和最佳实践
4. 生成结构化的Markdown报告

📋 报告格式：
- 清晰的标题结构
- 关键指标表格展示
- 问题和建议分类列出
- 包含操作建议和命令示例

⚠️ **重要：** 只能基于k8s_admin提供的真实数据生成报告""",
        tools=[],
        model_client_stream=True,
    )

    user = UserProxyAgent(
        name="user",
        input_func=user_action_func,
    )

    termination = TextMentionTermination("不同意", sources=["user"])
    group_chat = RoundRobinGroupChat(
        [k8s_admin, k8s_report, user], termination_condition=termination
    )

    cl.user_session.set("team", group_chat)

    # 发送连接指导消息
    welcome_msg = """🚀 **K8s Agent 已启动！**

📋 **使用前请先连接MCP服务器：**

1. 点击右侧边栏的 "Connect MCP Server" 
2. 选择 "SSE Server"
3. 输入MCP服务器地址，例如：
   ```
   http://localhost:8080/sse
   ```
4. 点击连接并等待成功

✅ 连接成功后，您就可以查询真实的K8s集群数据了！

🔧 **可用命令示例：**
- "查询所有Pod状态"
- "显示集群节点信息" 
- "获取Service列表"
- "分析集群资源使用情况"
"""
    await cl.Message(content=welcome_msg).send()

    print("✅ 聊天会话初始化完成")


# 新增：导出聊天记录的函数
@cl.action_callback("export_chat")
async def export_chat_history(action: cl.Action):
    chat_history = cl.user_session.get("chat_history", [])

    if not chat_history:
        await cl.Message(content="当前没有聊天记录可以导出。").send()
        return

    export_content = []
    for message in chat_history:
        if message.get("author") == "user":
            export_content.append(f"用户: {message.get('content', '')}")
        elif message.get("author") == "assistant":
            export_content.append(f"AI助手: {message.get('content', '')}")
        # 可以根据需要添加更多消息类型或自定义格式

    export_text = "\n\n".join(export_content)

    # 修复：使用消息发送文件，而不是直接调用File.send()
    file_element = cl.File(
        name="chat_history.txt",
        content=export_text.encode("utf-8"),
        mime="text/plain",
    )

    # 通过消息发送文件
    await cl.Message(content="📁 聊天记录已导出！", elements=[file_element]).send()


@cl.on_message
async def chat(message: cl.Message) -> None:
    # 🔧 新增：用户消息长度Debug
    log_length_debug("用户输入消息", message.content, {"消息类型": "用户查询"})

    # 检查MCP连接状态
    mcp_tools = cl.user_session.get("mcp_tools", {})

    print("🔍 调试信息:")
    print(f"  - MCP工具数量: {sum(len(tools) for tools in mcp_tools.values())}")

    if not mcp_tools:
        connection_status = """❌ **MCP连接失败！**

🔧 **解决步骤：**
1. 确认K8s MCP服务器正在运行
2. 在Chainlit界面右侧边栏点击"Connect MCP Server"
3. 选择"SSE Server"并输入服务器地址（如：http://localhost:8080/sse）
4. 等待连接成功后重新发送消息

📡 **当前状态：** 未检测到任何MCP连接"""

        log_length_debug("MCP连接失败响应", connection_status, {"响应类型": "错误提示"})
        await cl.Message(content=connection_status).send()
        return

    # 显示连接状态
    total_tools = sum(len(tools) for tools in mcp_tools.values())
    if total_tools > 0:
        connection_status = "📡 **MCP连接状态：**\n\n"
        for name, tool_list in mcp_tools.items():
            connection_status += f"✅ **{name}:** {len(tool_list)} 个工具\n"
            for tool in tool_list[:3]:
                connection_status += f"   - `{tool['name']}`\n"
            if len(tool_list) > 3:
                connection_status += f"   - ... 还有 {len(tool_list) - 3} 个工具\n"

        connection_status += (
            f"\n🔧 **总计：** {total_tools} 个可用工具，现在可以查询K8s数据了！"
        )
        print(connection_status)

    # 确保Agent拥有最新的工具列表
    await update_agents_with_tools()

    # 获取team并处理消息
    team = cast(RoundRobinGroupChat, cl.user_session.get("team"))
    streaming_response: cl.Message | None = None

    # 在cl.on_message中捕获聊天记录
    chat_history = cl.user_session.get("chat_history", [])
    chat_history.append({"author": "user", "content": message.content})
    cl.user_session.set("chat_history", chat_history)

    # 用于存储最后的响应消息
    last_response_content = ""

    # 🔧 新增：流式响应长度统计
    streaming_stats = {
        "chunk_count": 0,
        "total_chars": 0,
        "max_chunk_size": 0,
        "chunks_over_limit": 0,
    }

    # 🔧 回退到原始的流式处理逻辑，但添加异常处理
    try:
        async for msg in team.run_stream(
            task=[TextMessage(content=message.content, source="user")],
            cancellation_token=CancellationToken(),
        ):
            if isinstance(msg, ModelClientStreamingChunkEvent):
                chunk_content = msg.content or ""
                chunk_length = len(chunk_content)

                # 🔧 更新流式统计
                streaming_stats["chunk_count"] += 1
                streaming_stats["total_chars"] += chunk_length
                streaming_stats["max_chunk_size"] = max(
                    streaming_stats["max_chunk_size"], chunk_length
                )

                if chunk_length > 100:  # 大块内容统计
                    streaming_stats["chunks_over_limit"] += 1

                # 每100个chunk记录一次Debug信息
                if streaming_stats["chunk_count"] % 100 == 0:
                    log_length_debug(
                        "流式响应进度",
                        last_response_content,
                        {
                            "已处理chunk数": streaming_stats["chunk_count"],
                            "累计字符数": streaming_stats["total_chars"],
                            "最大chunk大小": streaming_stats["max_chunk_size"],
                            "大块数量": streaming_stats["chunks_over_limit"],
                        },
                    )

                if streaming_response is None:
                    streaming_response = cl.Message(content="", author=msg.source)
                await streaming_response.stream_token(chunk_content)
                last_response_content += chunk_content  # 收集响应内容
            elif streaming_response is not None:
                await streaming_response.send()
                streaming_response = None
            elif isinstance(msg, TaskResult):
                final_message = "Task terminated. "
                if msg.stop_reason:
                    final_message += msg.stop_reason

                log_length_debug(
                    "任务终止消息",
                    final_message,
                    {"终止原因": msg.stop_reason or "未知"},
                )
                await cl.Message(content=final_message).send()
            else:
                pass
    except Exception as e:
        # 🔧 捕获并处理所有异常，包括GeneratorExit
        print(f"流式处理异常: {e}")
        log_length_debug(
            "流式处理异常",
            str(e),
            {
                "异常类型": type(e).__name__,
                "已处理chunk数": streaming_stats["chunk_count"],
                "累计字符数": streaming_stats["total_chars"],
            },
        )

        if streaming_response is not None:
            await streaming_response.send()
        # 如果没有响应内容，发送错误消息
        if not last_response_content.strip():
            await cl.Message(content="❌ 处理请求时出现问题，请重试").send()

    # 🔧 新增：最终响应长度Debug
    if last_response_content:
        log_length_debug(
            "最终AI响应",
            last_response_content,
            {
                "响应来源": "AI助手",
                "流式chunk总数": streaming_stats["chunk_count"],
                "最大chunk大小": streaming_stats["max_chunk_size"],
                "大块数量": streaming_stats["chunks_over_limit"],
            },
        )

        chat_history.append({"author": "assistant", "content": last_response_content})
        cl.user_session.set("chat_history", chat_history)

    # 新增：在每次聊天结束后，如果有聊天记录，就显示导出按钮
    updated_chat_history = cl.user_session.get("chat_history", [])
    if len(updated_chat_history) >= 2:  # 至少有一轮对话（用户+助手）
        await cl.Message(
            content="💬 对话记录已更新，您可以导出聊天记录：",
            actions=[
                cl.Action(
                    name="export_chat",
                    payload={"value": "export_chat_history"},
                    label="📁 导出聊天记录",
                    description="导出当前会话的聊天记录。",
                )
            ],
        ).send()


# 🔧 备选方案：更安全的流式处理
async def chat_with_streaming(message: cl.Message) -> None:
    """备选的流式处理版本"""
    # ... 前面的代码相同 ...

    try:
        streaming_response: cl.Message | None = None
        last_response_content = ""
        message_count = 0
        total_chars = 0

        # 🔧 使用 aclose() 来正确关闭 async generator
        stream = cl.run_stream(
            task=[TextMessage(content=message.content, source="user")],
            cancellation_token=CancellationToken(),
        )

        try:
            async for msg in stream:
                message_count += 1

                # 🔧 更严格的限制，防止payload过大
                if message_count > 30 or total_chars > 1000:
                    print("⚠️ 达到消息限制，停止处理")
                    break

                if isinstance(msg, ModelClientStreamingChunkEvent):
                    chunk_content = msg.content or ""
                    total_chars += len(chunk_content)

                    if streaming_response is None:
                        streaming_response = cl.Message(
                            content="", author=msg.source or "assistant"
                        )

                    await streaming_response.stream_token(chunk_content)
                    last_response_content += chunk_content

                elif streaming_response is not None:
                    await streaming_response.send()
                    streaming_response = None

                elif isinstance(msg, TaskResult):
                    final_message = "✅ 任务完成"
                    if msg.stop_reason:
                        final_message += f" ({msg.stop_reason})"
                    await cl.Message(content=final_message).send()

        except GeneratorExit:
            print("🔄 流式处理被正常终止")
        finally:
            # 🔧 确保正确关闭 async generator
            await stream.aclose()

            # 确保最后的响应被发送
            if streaming_response is not None:
                await streaming_response.send()

    except Exception as e:
        error_msg = f"❌ 流式处理错误: {str(e)[:100]}"
        await cl.Message(content=error_msg).send()

    # ... 后续代码相同 ...


# 🔧 新增：专门的节点格式化函数
def format_node_list_comprehensive(nodes: List[dict]) -> str:
    """专门为Node列表设计的格式化函数"""
    total_count = len(nodes)

    print(f"🔍 开始格式化 {total_count} 个Node")

    # 🔧 Node格式化Debug
    log_length_debug(
        "Node格式化开始",
        "",
        {"Node总数": total_count, "格式化类型": "Node综合列表"},
    )

    # Node数量通常不多，直接显示完整列表
    report = "📊 **Kubernetes 集群节点状态报告**\n\n"
    report += f"🔢 **节点总数：** {total_count} 个节点\n\n"

    # 生成Node统计信息
    stats = generate_node_statistics(nodes)
    log_length_debug("Node统计生成", stats, {"统计类型": "Node统计信息"})
    report += stats + "\n"

    # 生成详细的节点表格
    report += "📋 **节点详细信息：**\n\n"
    table = format_node_table_detailed(nodes)
    log_length_debug("Node详细表格", table, {"表格类型": "Node详细信息"})
    report += table

    # 添加节点健康状况分析
    health_analysis = analyze_node_health(nodes)
    report += f"\n\n{health_analysis}"

    log_length_debug(
        "Node最终报告",
        report,
        {"节点数量": total_count, "报告类型": "完整节点报告"},
    )

    print(f"✅ Node报告生成完成，总长度: {len(report)}")
    return report


def generate_node_statistics(nodes: List[dict]) -> str:
    """生成Node统计信息"""
    stats_text = "📈 **节点统计信息：**\n"

    # 统计节点状态
    status_counts = {}
    role_counts = {}
    version_counts = {}

    for node in nodes:
        if isinstance(node, dict):
            # 状态统计
            status = extract_node_status(node)
            status_counts[status] = status_counts.get(status, 0) + 1

            # 角色统计
            roles = extract_node_roles(node)
            role_counts[roles] = role_counts.get(roles, 0) + 1

            # 版本统计
            version = extract_node_version(node)
            if version != "Unknown":
                version_counts[version] = version_counts.get(version, 0) + 1

    # 节点状态分布
    if status_counts:
        stats_text += "**节点状态：** "
        status_info = [f"{status}({count})" for status, count in status_counts.items()]
        stats_text += ", ".join(status_info) + "\n"

    # 节点角色分布
    if role_counts:
        stats_text += "**节点角色：** "
        role_info = [f"{role}({count})" for role, count in role_counts.items()]
        stats_text += ", ".join(role_info) + "\n"

    # Kubernetes版本分布
    if version_counts:
        stats_text += "**K8s版本：** "
        version_info = [f"{ver}({count})" for ver, count in version_counts.items()]
        stats_text += ", ".join(version_info) + "\n"

    return stats_text


def format_node_table_detailed(nodes: List[dict]) -> str:
    """生成详细的Node表格"""
    if not nodes:
        return "没有节点数据"

    headers = [
        "节点名称",
        "状态",
        "角色",
        "版本",
        "内部IP",
        "外部IP",
        "OS镜像",
        "运行时间",
    ]

    # 构建表格
    table = "| " + " | ".join(headers) + " |\n"
    table += "| " + " | ".join(["---"] * len(headers)) + " |\n"

    for node in nodes:
        if isinstance(node, dict):
            # 节点名称
            name = extract_node_field(node, "name")

            # 节点状态
            status = extract_node_status(node)

            # 节点角色
            roles = extract_node_roles(node)

            # K8s版本
            version = extract_node_version(node)

            # IP地址
            internal_ip, external_ip = extract_node_ips(node)

            # OS镜像
            os_image = extract_node_os_image(node)

            # 运行时间
            age = extract_node_age(node)

            row_values = [
                name,
                status,
                roles,
                version,
                internal_ip,
                external_ip,
                os_image,
                age,
            ]

            # 清理和截断值
            cleaned_values = []
            for i, value in enumerate(row_values):
                value = str(value).replace("\n", " ").replace("|", "\\|")
                max_length = 30 if i == 0 else 20  # 节点名称可以更长
                if len(value) > max_length:
                    value = value[: max_length - 3] + "..."
                cleaned_values.append(value)

            table += "| " + " | ".join(cleaned_values) + " |\n"

    return table


def extract_node_field(node: dict, field_type: str) -> str:
    """提取节点字段的通用函数"""
    if field_type == "name":
        # 尝试多种可能的名称字段
        name = node.get("name") or node.get("Name")
        if not name and "metadata" in node:
            name = node["metadata"].get("name")
        return name or "Unknown"

    return "Unknown"


def extract_node_status(node: dict) -> str:
    """提取节点状态"""
    # 尝试不同的状态字段
    status = node.get("status")
    if isinstance(status, dict):
        # 从conditions中提取Ready状态
        conditions = status.get("conditions", [])
        if isinstance(conditions, list):
            for condition in conditions:
                if isinstance(condition, dict) and condition.get("type") == "Ready":
                    return "Ready" if condition.get("status") == "True" else "NotReady"

        # 尝试其他状态字段
        phase = status.get("phase")
        if phase:
            return phase

    # 直接的状态字段
    direct_status = node.get("Status")
    if direct_status:
        return str(direct_status)

    return "Unknown"


def extract_node_roles(node: dict) -> str:
    """提取节点角色"""
    # 尝试直接的roles字段
    roles = node.get("roles") or node.get("Roles")
    if roles:
        if isinstance(roles, list):
            return ",".join(roles) if roles else "worker"
        return str(roles)

    # 从metadata.labels中提取角色
    metadata = node.get("metadata", {})
    if isinstance(metadata, dict):
        labels = metadata.get("labels", {})
        if isinstance(labels, dict):
            # 检查常见的角色标签
            if "node-role.kubernetes.io/control-plane" in labels:
                return "control-plane"
            elif "node-role.kubernetes.io/master" in labels:
                return "master"
            elif "node-role.kubernetes.io/worker" in labels:
                return "worker"

            # 检查其他角色标签
            for key in labels.keys():
                if "node-role.kubernetes.io/" in key:
                    role = key.replace("node-role.kubernetes.io/", "")
                    return role

    return "worker"


def extract_node_version(node: dict) -> str:
    """提取节点Kubernetes版本"""
    # 尝试直接的version字段
    version = node.get("version") or node.get("Version")
    if version:
        if isinstance(version, dict):
            return version.get(
                "kubeletVersion", version.get("kubeProxyVersion", "Unknown")
            )
        return str(version)

    # 从status.nodeInfo中提取
    status = node.get("status", {})
    if isinstance(status, dict):
        node_info = status.get("nodeInfo", {})
        if isinstance(node_info, dict):
            kubelet_version = node_info.get("kubeletVersion")
            if kubelet_version:
                return kubelet_version

    return "Unknown"


def extract_node_ips(node: dict) -> tuple[str, str]:
    """提取节点IP地址"""
    internal_ip = "Unknown"
    external_ip = "Unknown"

    # 尝试直接的IP字段
    if "internal-ip" in node:
        internal_ip = str(node["internal-ip"])
    if "external-ip" in node:
        external_ip = str(node["external-ip"])

    # 从status.addresses中提取
    status = node.get("status", {})
    if isinstance(status, dict):
        addresses = status.get("addresses", [])
        if isinstance(addresses, list):
            for addr in addresses:
                if isinstance(addr, dict):
                    addr_type = addr.get("type", "")
                    addr_value = addr.get("address", "")
                    if addr_type == "InternalIP":
                        internal_ip = addr_value
                    elif addr_type == "ExternalIP":
                        external_ip = addr_value

    return internal_ip, external_ip


def extract_node_os_image(node: dict) -> str:
    """提取节点OS镜像信息"""
    # 从status.nodeInfo中提取
    status = node.get("status", {})
    if isinstance(status, dict):
        node_info = status.get("nodeInfo", {})
        if isinstance(node_info, dict):
            os_image = node_info.get("osImage")
            if os_image:
                # 简化OS镜像信息
                return (
                    str(os_image).split()[0] if " " in str(os_image) else str(os_image)
                )

    return "Unknown"


def extract_node_age(node: dict) -> str:
    """提取节点运行时间"""
    # 尝试直接的age字段
    age = node.get("age") or node.get("Age")
    if age:
        return str(age)

    # 从metadata.creationTimestamp计算
    metadata = node.get("metadata", {})
    if isinstance(metadata, dict):
        creation_timestamp = metadata.get("creationTimestamp")
        if creation_timestamp:
            # 简化时间戳显示
            return str(creation_timestamp)[:10]  # 只显示日期部分

    return "Unknown"


def analyze_node_health(nodes: List[dict]) -> str:
    """分析节点健康状况"""
    health_report = "🏥 **节点健康状况分析：**\n"

    ready_nodes = []
    not_ready_nodes = []
    unknown_nodes = []

    for node in nodes:
        name = extract_node_field(node, "name")
        status = extract_node_status(node)

        if status == "Ready":
            ready_nodes.append(name)
        elif status == "NotReady":
            not_ready_nodes.append(name)
        else:
            unknown_nodes.append(name)

    # 健康状况统计
    total_nodes = len(nodes)
    health_report += f"• **正常节点：** {len(ready_nodes)}/{total_nodes} ({len(ready_nodes) / total_nodes * 100:.1f}%)\n"

    if not_ready_nodes:
        health_report += f"• **异常节点：** {len(not_ready_nodes)} 个 - {', '.join(not_ready_nodes[:3])}\n"
        if len(not_ready_nodes) > 3:
            health_report += f"  还有 {len(not_ready_nodes) - 3} 个异常节点\n"

    if unknown_nodes:
        health_report += f"• **状态未知：** {len(unknown_nodes)} 个节点\n"

    # 集群健康评估
    if len(ready_nodes) == total_nodes:
        health_report += "\n✅ **集群状态：** 所有节点运行正常"
    elif len(ready_nodes) >= total_nodes * 0.8:
        health_report += "\n🟡 **集群状态：** 大部分节点正常，需要关注异常节点"
    else:
        health_report += "\n🔴 **集群状态：** 多个节点异常，需要立即处理"

    return health_report
